java中被加载进内存的类都可以认为对应着一个类对象示例。也可以反过来认为,class文件是类对象序列化后的结果。类对象包含指定类型的meta data,包括method,constructor,field等。JVM加载类的过程就是生成类对象的过程。.class文件对人类是不可读的,使用javap工具可以阅读。

// 遍历类public method
Class<?> clz = ...;
for (Method meth:clz.getMethods()) {
    // do something
}

类加载的本质是从类字节数据(表示为一个字节数组)构造出类对象,由ClassLoader.defineClass实现。尽管ClassLoader没有未实现的接口,其仍然被声明为abstract类,目的是禁止直接使用此类,需要通过继承使用。

// ClassLoader 示例
class MyClassLoader extends ClassLoader {
        public Class<?> getClass(String name, byte[] b) {
            return super.defineClass(name, b, 0, b.length);
        }
    }

类加载器有多个继承层次,可以通过继承实现自己的类加载器。从各种源(只要是字节流)加载类。

反射是java提供的一套api。可以在完全不知道对象类型的情况下操纵对象并实现多态。其主要逻辑是通过查询向对象动态获取各种meta data。

Java reflection allows an object to look in the mirror and discover what fields, methods, and constructors it has.

Method对象是反射API提供的对象中最常用的,constructor和field对象类似。对象通过“查询”(look in the mirror)获得自己有的method对象。

try {
    // 创建一个 String 对象
    String str = "Hello, World!";

    // 将 String 引用转换为 Object 引用
    Object obj = str;

    // 获取 Object 类的 Class 对象
    Class<?> objectClass = obj.getClass();

    // 获取 hashCode 方法
    Method hashCodeMethod = objectClass.getMethod("hashCode");

    // 调用 hashCode 方法
    int hashCode = (int) hashCodeMethod.invoke(obj);

    // 输出 hashCode 值
    System.out.println("HashCode of the string: " + hashCode);
} catch (NoSuchMethodException e) {
    System.err.println("Method not found: " + e.getMessage());
} catch (SecurityException e) {
    System.err.println("Security exception: " + e.getMessage());
} catch (IllegalAccessException e) {
    System.err.println("Illegal access: " + e.getMessage());
} catch (IllegalArgumentException e) {
    System.err.println("Illegal argument: " + e.getMessage());
} catch (Exception e) {
    System.err.println("An unexpected error occurred: " + e.getMessage());
}

脱裤子放屁?

明明我们可以直接将指向String的Object引用类型转换为String引用,然后自由使用hashcode方法。为什么要大费周章地使用反射?

注意,上面的例子只是一个简单的示例,目的在于展示反射的书写内容。反射的目标是在我们对对象一无所知的时候,让对象自省得知自己的类是什么。并且可以截获对象的方法调用。相当于得到了动态调整对象的空间。比如proxy类,目标是可以截获所有类的方法调用。强制类型转换本质上是一种静态代码,但是在实现proxy的时候,你没有办法为每个方法都书写代理代码。只能通过反射截获method call。

总之,当你想要动态实现针对所有对象的操作时,请用反射。